package concurrecy.lock2;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 不可重入锁
 */
class JannaLock implements Lock {

    private AtomicInteger state = new AtomicInteger(0);
    private ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue<>();
    private Thread owner = null;

    @Override
    public boolean tryLock() {
        // 从0改为1加锁成功。否则加锁失败
        if(state.compareAndSet(0, 1)) {
            owner = Thread.currentThread();
            return true;
        }
        return false;
    }

    @Override
    public void lock() {
        Thread currentThread = Thread.currentThread();
        if(!tryLock()) {
            waiters.add(currentThread);
            for(;;) {
                if(tryLock()) {
                    waiters.remove(currentThread);
                    return;
                }
                LockSupport.park();
            }
        }
    }

    @Override
    public void unlock() {
        if(Thread.currentThread() != owner)
            throw new IllegalMonitorStateException("owner: " + owner);
        owner = null;
        Thread peek = waiters.peek();
        state.set(0);
        if(peek != null)
            LockSupport.unpark(peek);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

/**
 *
 */
public class MyLockDemo {
    /**
     * 测试多线程获取锁
     * @param lock
     */
    static void test2(Lock lock) {
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.shutdown();
    }

    /**
     * 测试多线程竞争
     */
    static void test3(Lock lock, int n) throws InterruptedException {
        class Data {
            int x = 0;
        }
        final Data data = new Data();
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(n);
        long point = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            executorService.execute(() -> {
                for (int j = 0; j < 100_000; j++) {
                    lock.lock();
                    try {
                        data.x ++;
                    } finally {
                        lock.unlock();
                    }
                }
                latch.countDown();
            });
        }
        latch.await();
        System.out.println("use " + (System.currentTimeMillis() - point));
        executorService.shutdown();
        System.out.println(data.x);
    }

    public static void main(String[] args) throws InterruptedException {
        Lock lock = new JannaLock();
//        Lock lock = new ReentrantLock();
//        test2(lock);
        test3(lock, 8);
    }
}
